﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Linn {
    public abstract class Parameter<T> : IParameter<T> {
        protected Parameter(string name)
            : this(name, true, default(T), false) { }

        protected Parameter(string name, bool editable)
            : this(name, editable, default(T), false) { }

        protected Parameter(string name, bool editable, T defaultValue)
            : this(name, editable, defaultValue, false) { }

        protected Parameter(string name, bool editable, T defaultValue, bool required) {
            this.Name = name;
            this.Editable = editable;
            this.Default = defaultValue;
            this.Required = required;
        }

        public string Name { get; private set; }
        
        public bool Editable { get; private set; }

        public abstract DataType DataType { get; }

        public T Default { get; private set; }

        public T Value { get; set; }

        object IParameter.Default {
            get { return this.Default; }
        }

        object IParameter.Value {
            get { return this.Value; }
            set {
                if (typeof(T).IsValueType && value == null) {
                    throw new ArgumentNullException("The value must be not null.");
                }

                this.Value = (T)value;
            }
        }

        public bool Required { get; private set; }
    }

    public class SecurityCodeParameter : Parameter<string> {
        public SecurityCodeParameter(string name)
            : base(name, true, string.Empty, false) { }

        public SecurityCodeParameter(string name, bool editable)
            : base(name, editable, string.Empty, false) { }

        public SecurityCodeParameter(string name, bool editable, string defaultValue)
            : base(name, editable, defaultValue, false) { }

        public SecurityCodeParameter(string name, bool editable, string defaultValue, bool required)
            : base(name, editable, defaultValue, required) {
        }

        public override DataType DataType { get { return Linn.DataType.SecurityCode; } }
    }

    public class StringParameter : Parameter<string> {
        public StringParameter(string name)
            : base(name, true, string.Empty, false) { }

        public StringParameter(string name, bool editable)
            : base(name, editable, string.Empty, false) { }

        public StringParameter(string name, bool editable, string defaultValue)
            : base(name, editable, defaultValue, false) { }

        public StringParameter(string name, bool editable, string defaultValue, bool required)
            : base(name, editable, defaultValue, required) {
        }

        public override DataType DataType { get { return Linn.DataType.String; } }
    }

    public class DateTimeParameter : Parameter<DateTime> {
        public DateTimeParameter(string name)
            : base(name, true, DateTime.MinValue, false) { }

        public DateTimeParameter(string name, bool editable)
            : base(name, editable, DateTime.MinValue, false) { }

        public DateTimeParameter(string name, bool editable, DateTime defaultValue)
            : base(name, editable, defaultValue, false) { }

        public DateTimeParameter(string name, bool editable, DateTime defaultValue, bool required)
            : base(name, editable, defaultValue, required) {
        }

        public override DataType DataType { get { return Linn.DataType.DateTime; } }
    }

    public class NumberParameter : Parameter<Number> {
        public NumberParameter(string name)
            : base(name, true, Number.NaN, false) { }

        public NumberParameter(string name, bool editable)
            : base(name, editable, Number.NaN, false) { }

        public NumberParameter(string name, bool editable, Number defaultValue)
            : base(name, editable, defaultValue, false) { }

        public NumberParameter(string name, bool editable, Number defaultValue, bool required)
            : base(name, editable, defaultValue, required) {
        }

        public override DataType DataType { get { return Linn.DataType.Number; } }
    }
}
